package com.ccnf.handler;

import com.ccnf.core.bean.TokenParams;
import com.ccnf.core.exception.BizException;
import com.ccnf.model.ao.PassToken;
import com.ccnf.model.ao.Role;
import com.ccnf.service.TokenService;
import com.ccnf.service.UserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

public class AuthenticationInterceptor implements HandlerInterceptor {
    @Autowired
    private TokenService tokenService;
    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) {
        if (request.getMethod().equalsIgnoreCase("OPTIONS")) {
            // 如果是OPTIONS请求则直接放行
            return true;
        }
        HandlerMethod handlerMethod;
        if (object instanceof HandlerMethod) {
            handlerMethod = (HandlerMethod) object;
        } else {
            // 如果不是映射到方法直接通过
            return true;
        }
        String requestURI = request.getRequestURI();
        if (!requestURI.contains("v1")
                || requestURI.contains("swagger-resources")
                || requestURI.contains("api-docs-ext")
                || requestURI.contains("api-docs")
                || requestURI.endsWith(".html")) {
            // 如果映射的路径包含swagger
            return true;
        }
        response.setHeader("Access-Control-Allow-Origin", "*");
        String token = request.getHeader("authorization");// 从 http 请求头中取出 token
        // 执行认证
        Method method = handlerMethod.getMethod();
        if (StringUtils.isEmpty(token)) {
            //检查是否有@passToken注释，有则跳过认证
            if (method.isAnnotationPresent(PassToken.class)) {
                // 如果是带PassToken注解
                request.setAttribute("TP", new TokenParams(null, null, null));
                return true;
            }
            throw new BizException(401, "无token，请重新登录");
        }
        try {
            Claims claims = tokenService.verifyJwtByJJwt(token);// 验证 token
            Long userId = claims.get("userId", Long.class);
            Long expoId = claims.get("expoId", Long.class);
            String channelCode = claims.get("channelCode", String.class);
            TokenParams tokenParams = new TokenParams(userId, expoId, channelCode);
            if (method.isAnnotationPresent(Role.class)){
                Role role = handlerMethod.getMethod().getAnnotation(Role.class);
                userService.validateRole(tokenParams, role.roleType());
            }
            request.setAttribute("TP", tokenParams);
            return true;
        } catch (ExpiredJwtException e) {
            throw new BizException(401, "令牌已过期");
        } catch (UnsupportedJwtException e) {
            throw new BizException(401, "不支持的令牌格式");
        } catch (MalformedJwtException e) {
            throw new BizException(401, "无效令牌");
        } catch (SignatureException e) {
            throw new BizException(401, "令牌签名验证失败");
        } catch (IllegalArgumentException e) {
            throw new BizException(401, "令牌参数错误");
        }
    }
}